package gnss

import (
	"dgo/goutils/utils"
	"fmt"
	"strings"
)

/*
**

	输入Msm, 如果一个历元满了, 就触发OnRtcmRawObsEpochEnd事件
*/
type RtcmRawObsEpochInput struct {
	resetflag            byte
	curr                 *RtcmRawObsEpoch
	OnRtcmRawObsEpochEnd func(epoch *RtcmRawObsEpoch)
}

func NewRtcmRawObsEpochInput() *RtcmRawObsEpochInput {
	rval := &RtcmRawObsEpochInput{}
	return rval
}

func (this *RtcmRawObsEpochInput) Close() {
	if this.curr != nil {
		if this.OnRtcmRawObsEpochEnd != nil {
			this.OnRtcmRawObsEpochEnd(this.curr)
		}
		this.curr = nil
	}
}

func (this *RtcmRawObsEpochInput) CurrentEpoch() *RtcmRawObsEpoch {
	return this.curr
}

func (this *RtcmRawObsEpochInput) ResetForNextInput() {
	this.resetflag = 1
}

/*
*
返回

	true: 表示一个历元已经完成

要判断一个历元是否完成
add_check_fn: 判断是否需要添加到列表
*/
func (this *RtcmRawObsEpochInput) InputMsm(msm RtcmRawMsm) bool {
	if this.curr == nil || this.resetflag == 1 {
		this.curr = NewRtcmRawObsEpoch()
		this.resetflag = 0
	}

	this.curr.AddObs(msm)

	if (this.curr.TOW != msm.GetHeader().GetTOW()) || msm.GetHeader().EpochEndFlag {
		if this.curr.Count() > 0 {
			if this.OnRtcmRawObsEpochEnd != nil {
				this.OnRtcmRawObsEpochEnd(this.curr)
			}
		}

		this.ResetForNextInput()
		return true
	}

	return false
}

/*
**

	编码时的常量
*/
type RtcmObsVars struct {
	Cp [NAVI_SYS_MAX][64][32]float64 /* carrier-phase measurement 编码时记录周跳常量 */
}

func (this *RtcmObsVars) GetCp(navisys, satid, sigid byte) float64 {
	return this.Cp[navisys][satid-1][sigid-1]
}

func (this *RtcmObsVars) SetCp(navisys, satid, sigid byte, v float64) {
	this.Cp[navisys][satid-1][sigid-1] = v
}

/**
 * 一个历元的数据, 包含多个系统
 */
type RtcmRawObsEpoch struct {
	TOW     uint32
	MsmType byte
	// 0 留空
	obsMap   [NAVI_SYS_MAX]*RtcmRawMsmObs
	n        int
	SortList []byte
}

func NewRtcmRawObsEpoch() *RtcmRawObsEpoch {
	rval := &RtcmRawObsEpoch{}
	return rval
}

func (this *RtcmRawObsEpoch) Reset() {
	for i := U8_0; i < NAVI_SYS_MAX; i++ {
		if this.obsMap[i] != nil {
			this.obsMap[i].Reset()
		}
	}
}

func (this *RtcmRawObsEpoch) Clean() {
	for i := U8_0; i < NAVI_SYS_MAX; i++ {
		if this.obsMap[i] != nil {
			this.obsMap[i].Clean()
		}
	}
}

func (this *RtcmRawObsEpoch) String() string {
	var bb utils.BytesBuilder
	for i := U8_0; i < NAVI_SYS_MAX; i++ {
		naviObs := this.obsMap[i]
		if naviObs != nil {
			naviObs.WriteString(&bb)
		}
	}
	return bb.String()
}

func (this *RtcmRawObsEpoch) StringWithRaw() string {
	var bb utils.BytesBuilder
	for i := U8_1; i < NAVI_SYS_MAX; i++ {
		naviObs := this.obsMap[i]
		if naviObs != nil {
			naviObs.WriteDetailWithRaw(&bb)
		}
	}
	return bb.String()
}

func (this *RtcmRawObsEpoch) SatNumString() string {
	var sb strings.Builder
	for i := U8_1; i < NAVI_SYS_MAX; i++ {
		naviObs := this.obsMap[i]
		if naviObs != nil {
			sb.WriteString(fmt.Sprintf("%s:%d; ", GNSS_SYS_RINEX_CHAR[naviObs.Header.NaviSys], naviObs.GetSatsN()))
		}
	}

	return sb.String()
}

func (this *RtcmRawObsEpoch) CopyFromYObsEpoch(yepoch *GnssYObsEpoch, vars *RtcmObsVars) {
	this.TOW = uint32(yepoch.TOW)
	for i := U8_0; i < NAVI_SYS_MAX-1; i++ {
		naviObs0 := this.obsMap[i+1]
		for j := U8_0; j < SATID_MAX; j++ {
			satObsy := yepoch.obsMap[i][j]
			if satObsy != nil && satObsy.Satid != 0 {

				if !satObsy.IsValid() {
					continue
				}

				if naviObs0 == nil {
					naviObs0 = NewRtcmRawMsmObs()
					this.obsMap[satObsy.NaviSys] = naviObs0
				}
				naviObs0.Header.NaviSys = satObsy.NaviSys
				naviObs0.Header.TOW = this.TOW
				naviObs0.Header.StaID = yepoch.StaID

				err := naviObs0.CopyFromYObs(satObsy, vars)
				if err != nil {
					utils.Log.WarnTypef("", "[%s][tow:%d]数据异常:%s", satObsy.GetPrnCode(), this.TOW, err.Error())
				}
			}
		}
	}
}

func (this *RtcmRawObsEpoch) AddObs(msm RtcmRawMsm) {
	this.TOW = msm.GetHeader().GetTOW()
	naviSys := msm.GetHeader().NaviSys
	raw := this.obsMap[naviSys]
	if raw == nil {
		raw = NewRtcmRawMsmObs()
		raw.Header.CopyInfoFrom(msm.GetHeader())
		raw.Header.NaviSys = naviSys
		this.obsMap[naviSys] = raw
		this.n++
	}
	msm.WriteToObs(raw)
}

func (this *RtcmRawObsEpoch) DelNaviSys(navisys byte) {
	if this.obsMap[navisys] != nil {
		this.obsMap[navisys].Reset()
	}
}

func (this *RtcmRawObsEpoch) RangeObs(fn func(obs *RtcmRawMsmObs)) {
	l := len(this.obsMap)

	for navsys := U8_0; navsys < byte(l); navsys++ {
		rval := this.obsMap[navsys]
		if rval != nil && rval.IsValid() {
			fn(rval)
		}
	}
}

func (this *RtcmRawObsEpoch) CheckGetObs(navsys byte) (rval *RtcmRawMsmObs) {
	if int(navsys) >= len(this.obsMap) {
		return nil
	}
	rval = NewRtcmRawMsmObs()
	this.obsMap[navsys] = rval
	return
}

func (this *RtcmRawObsEpoch) GetObs(navsys byte) *RtcmRawMsmObs {
	if int(navsys) >= len(this.obsMap) {
		return nil
	}
	return this.obsMap[navsys]
}

func (this *RtcmRawObsEpoch) NextObsBySortList(navsys byte) (rval *RtcmRawMsmObs) {
	startidx := -1
	rval = nil
	if navsys == 0 {
		startidx = 0
	} else {
		for i := 0; i < len(this.SortList); i++ {
			if this.SortList[i] == navsys {
				startidx = i + 1
				break
			}
		}
		if startidx == -1 {
			return nil
		}
	}
	for i := startidx; i < len(this.SortList); i++ {
		navsys = this.SortList[i]
		rval = this.obsMap[navsys]
		if rval != nil && rval.IsValid() {
			return rval
		}
	}
	return nil
}

func (this *RtcmRawObsEpoch) NextObs(navsys byte) *RtcmRawMsmObs {
	navsys++
	l := len(this.obsMap)
	if int(navsys) >= l {
		return nil
	}

	for ; navsys < byte(l); navsys++ {
		rval := this.obsMap[navsys]
		if rval != nil && rval.IsValid() {
			return rval
		}
	}

	return nil
}

/*
*
msm 的数量
*/
func (this *RtcmRawObsEpoch) Count() int {
	return this.n
}
